package com.sen.rbac.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.sen.common.common.constrant.CommonConstrant;
import com.sen.common.common.enums.CommonEnum;
import com.sen.common.common.response.MessageResult;
import com.sen.common.common.util.SnowflakeIdWorker;
import com.sen.common.common.util.TreeUtils;
import com.sen.common.user.config.UserContextHolder;
import com.sen.rbac.constant.RbacConstant;
import com.sen.rbac.dto.SysResourceDto;
import com.sen.rbac.enums.RbacMsgEnum;
import com.sen.rbac.exception.RbacException;
import com.sen.rbac.mapper.SysResourceDao;
import com.sen.rbac.mapper.SysRoleAccountDao;
import com.sen.rbac.model.SysResource;
import com.sen.rbac.model.SysRoleAccount;
import com.sen.rbac.service.ResourceService;
import com.sen.rbac.vo.SysResourceVO;
import lombok.extern.slf4j.Slf4j;
import org.modelmapper.ModelMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import java.util.stream.Collectors;

import static com.sen.rbac.enums.RbacMsgEnum.RESOURCE_CRUD_FAILED;
import static com.sen.rbac.enums.RbacMsgEnum.account_is_blank;


/**
 * @author esjiang
 */
@Service
@Slf4j
public class ResourceServiceImpl implements ResourceService {

    @Resource
    SysResourceDao sysResourceDao ;

    @Resource
    ModelMapper modelMapper ;

    @Resource
    SysRoleAccountDao sysRoleAccountDao ;

    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public MessageResult crudResource(SysResourceDto sysResourceDto)  {
        MessageResult messageResult = MessageResult.bizFailed(RESOURCE_CRUD_FAILED);
        String operationType = sysResourceDto.getOperationType();
        if (StrUtil.equals(operationType, RbacConstant.ADD)){
            if (add(sysResourceDto)){
                messageResult = MessageResult.success() ;
            }
        }
        if (StrUtil.equals(operationType,RbacConstant.UPD)){
            try {
                if (update(sysResourceDto)){
                    messageResult = MessageResult.success() ;
                }
            }catch (RbacException e){
                log.error(e.getRespCodeEnum().toString(),e);
                return MessageResult.bizFailed(e.getRespCodeEnum()) ;
            }
        }
        if (StrUtil.equals(operationType,RbacConstant.DEL)){
            try {
                if (delete(sysResourceDto)){
                    messageResult = MessageResult.success() ;
                }
            }catch (RbacException e){
                log.error(e.getRespCodeEnum().toString(),e);
                return MessageResult.bizFailed(e.getRespCodeEnum()) ;
            }
        }
        if (StrUtil.equals(operationType,RbacConstant.LIST)){
            Set<SysResourceVO> list = list(sysResourceDto);
            messageResult = MessageResult.success(list);
        }
        return messageResult ;
    }

    @Override
    public List<SysResource> getResourcesByUserNameForGateway(String userName) {
        List<SysResource> sysResources = CollectionUtil.newArrayList() ;
        /** 平台管理员有所有资源权限 */
        if (StrUtil.equals(CommonConstrant.SUPER_ADMIN,userName)){
            return sysResourceDao.selectList(Wrappers.<SysResource>lambdaQuery());
        }
        List<SysRoleAccount> sysRoleAccounts = sysRoleAccountDao.selectList(Wrappers.<SysRoleAccount>lambdaQuery().eq(SysRoleAccount::getUserName, userName));
        if (CollectionUtil.isNotEmpty(sysRoleAccounts)){
            List<String> collect = sysRoleAccounts.stream().map(sysRoleAccount -> sysRoleAccount.getRoleCode()).collect(Collectors.toList());
            sysResources = sysResourceDao.findResourceByRoleCode(collect);
        }
        /** 增加不鉴权的资源 **/
        sysResources.addAll(sysResourceDao.selectList(Wrappers.<SysResource>lambdaQuery().eq(SysResource::getAuthorization, CommonEnum.ENABLE_NO.getCode()))) ;
        return sysResources ;
    }

    private boolean add(SysResourceDto sysResourceDto){
        SysResource sysResource = modelMapper.map(sysResourceDto, SysResource.class);
        sysResource.setCode(SnowflakeIdWorker.generateId().toString());
        return sysResourceDao.insert(sysResource) == 1 ;
    }

    private boolean update(SysResourceDto sysResourceDto) throws RbacException {
        SysResource sysResource = modelMapper.map(sysResourceDto, SysResource.class);
        SysResource sourceSysResource = getSysResource(sysResourceDto.getCode());
        sysResource.setId(sourceSysResource.getId());
        return sysResourceDao.update(sysResource, Wrappers.<SysResource>lambdaQuery().eq(SysResource::getCode,sysResourceDto.getCode())) == 1 ;
    }

    private boolean delete(SysResourceDto sysResourceDto) throws RbacException {
        SysResource sysResource = getSysResource(sysResourceDto.getCode());
        if (ObjectUtil.isEmpty(sysResource)){
            throw new RbacException(RbacMsgEnum.resource_not_exist);
        }
        if (CollectionUtil.isNotEmpty(getChildren(sysResource))){
            throw new RbacException(RbacMsgEnum.RESOURCE_EXIST_CHILDREN);
        }
        return sysResourceDao.delete(Wrappers.<SysResource>lambdaQuery().eq(SysResource::getCode,sysResourceDto.getCode())) == 1;
    }

    private Set<SysResourceVO> list(SysResourceDto sysResourceDto){
        Set<SysResourceVO> voList = new TreeSet<>() ;
        String user = UserContextHolder.getUser();
        if (StrUtil.isBlank(user)){
            throw new RbacException(account_is_blank) ;
        }
        /**
         * 1，先找到角色
         * 2，再找到资源
         */
        /** admin在给区划分配资源的时候使用或admin账户登录 */
        List<SysResource> sysResources = CollUtil.newArrayList() ;
        if (UserContextHolder.isSuperAdmin()){
            sysResources = sysResourceDao.selectList(Wrappers.lambdaQuery());
        }else {
            sysResources = sysResourceDao.findResourceByUserNameTenantCodeSystemCodeEntityCode(user,sysResourceDto.getTenantCode() ,sysResourceDto.getEntityType());
        }
        /** 增加不鉴权的资源 **/
        if(!sysResourceDto.getUserType().equals("9")) {
            sysResources.addAll(sysResourceDao.selectList(Wrappers.<SysResource>lambdaQuery().eq(SysResource::getAuthorization, CommonEnum.ENABLE_NO.getCode())));
        }
        List<SysResourceVO> collect = sysResources.stream().map(p -> modelMapper.map(p, SysResourceVO.class))
                .distinct().collect(Collectors.toList());
        TreeUtils.buildTree(sysResourceDto.getSystemRootCode(),collect,voList);
        return voList ;
    }


    private List<SysResource> getChildren(SysResource sysResource){
        return sysResourceDao.selectList(Wrappers.<SysResource>lambdaQuery().eq(SysResource::getParentCode, sysResource.getCode()));
    }

    private SysResource getSysResource(String code){
        List<SysResource> sysResources = sysResourceDao.selectList(Wrappers.<SysResource>lambdaQuery().eq(SysResource::getCode,code));
        if (CollectionUtil.isEmpty(sysResources)){
            throw new RbacException(RbacMsgEnum.resource_not_exist);
        }
        if (sysResources.size() != 1 ){
            throw new RbacException(RbacMsgEnum.resource_data_exception);
        }
        return sysResources.get(0) ;
    }

}
